home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / bbmutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-25  |  40.4 KB  |  1,589 lines

  1. /*
  2.  *    Simple mail user interface for KA9Q IP/TCP package.
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *    Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
  8.  *    Permission granted for non-commercial copying and use, provided
  9.  *    this notice is retained.
  10.  *
  11.  *    Ported to NOS at 900120 by Anders Klemets SM0RGV.
  12.  *
  13.  *  Userlogging, 'RM' and 'KM' implementation,
  14.  *  more-prompts for all types
  15.  *  920307 and later, by Johan. K. Reinalda, WG7J/PA3DIS
  16.  *  920719 and later, by Brian A. Lantz, KO4KS
  17.  */
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <ctype.h>
  21. #include <time.h>
  22. #include <io.h>
  23. #include "global.h"
  24. #include "config.h"
  25. #include "ftpserv.h"
  26. #include "smtp.h"
  27. #include "proc.h"
  28. #include "usock.h"
  29. #include "socket.h"
  30. #include "telnet.h"
  31. #include "timer.h"
  32. #include "session.h"
  33. #include "files.h"
  34. #include "mailbox.h"
  35. #include "cmdparse.h"
  36. #include "bm.h"
  37. #include "mailutil.h"
  38.  
  39. #define        SETVBUF
  40. #if    defined(UNIX) || defined(MICROSOFT)
  41. #include    <sys/types.h>
  42. #endif
  43. /*
  44. #if    defined(UNIX) || defined(MICROSOFT) || defined(__TURBOC__)
  45. #include    <sys/stat.h>
  46. #endif
  47. #ifdef AZTEC
  48. #include <stat.h>
  49. #endif
  50. */
  51. #include <fcntl.h>
  52. #include "bm.h"
  53. #include "mailbox.h"
  54.  
  55. #ifdef SETVBUF
  56. #define        MYBUF    1024
  57. #endif
  58.  
  59. extern long ftell();
  60. char Badmsg[] = "Invalid Message number %d\n";
  61. char Nomail[] = "No messages\n";
  62. static char NoMsgs[] = "No message numbers given\n";
  63. static char anymore[] = "More(N=no)? ";
  64. static char Noaccess[] = "Unable to access %s\n";
  65. static int readnotes __ARGS((struct mbx *m, int already));
  66. static long isnewmail __ARGS((struct mbx *m));
  67. static int initnotes __ARGS((struct mbx *m));
  68. int lockit __ARGS((struct mbx *m));
  69. long fsize __ARGS((char *name));
  70. static void mfclose __ARGS((struct mbx *m));
  71.  
  72. #ifdef MAILBOX
  73.  
  74. static int
  75. initnotes(m)
  76. struct mbx *m;
  77. {
  78. register struct    let *cmsg;
  79. char buf[256];
  80. int     i, ret;
  81. int wasit = 0;
  82.  
  83.     if (m->mfile != NULLFILE)    {
  84.         fclose (m->mfile);
  85.         wasit = m->nmsgs;
  86.     }
  87.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  88.     if ((m->mfile = fopen(buf,READ_TEXT)) == NULLFILE)
  89.         return 0;
  90.     m->mboxsize = filelength (fileno(m->mfile));
  91.     if(!(m->sid & MBX_SID) && !stricmp(m->area,m->name)) /* our private mail area */
  92.         m->mysize = m->mboxsize;
  93.     m->nmsgs = 0;
  94.     m->change = 0;
  95.     m->newmsgs = 0;
  96.     m->anyread = 0;
  97.     /* Allocate space for reading messages */
  98.     readnotes(m, wasit);
  99. #ifdef USERLOG
  100.     m->current = 0; /*reset it*/
  101.     if (m->nmsgs)
  102.         for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++)
  103.             if ((cmsg->status & BM_READ) == 0) {
  104.                 m->current = i; /* first new message */
  105.                 break;
  106.             }
  107.  
  108.     /* start at one if no new messages */
  109.     if ((m->current == 0) && m->nmsgs)
  110.         m->current++;
  111. #endif
  112.     return 0;
  113. }
  114.  
  115. /* readnotes assumes that ifile is pointing to the first
  116.  * message that needs to be read.  For initial reads of a
  117.  * notesfile, this will be the beginning of the file.  For
  118.  * rereads when new mail arrives, it will be the first new
  119.  * message.
  120.  */
  121. static int
  122. readnotes(m, already)
  123. register struct mbx *m;
  124. int already;
  125. {
  126. register FILE *fp;
  127. char mailbox[100];
  128. long size;
  129. register int i, isit;
  130. register struct    let *cmsg;
  131. struct let *new;
  132.  
  133.     m->newmsgs = m->hmsgs = 0;
  134.     sprintf(mailbox,"%s/CONTROL/%s.ctl",Mailspool,m->area);
  135.     if((fp = fopen(mailbox,READ_BINARY)) != NULLFILE){
  136. #ifndef TNOS_68K
  137.         m->stdoutbuf = mallocw(MYBUF);
  138.         setvbuf(fp, m->stdoutbuf, _IOFBF, MYBUF);
  139. #endif
  140.         size = filelength (fileno(fp));
  141. /*        fseek (fp, 0L, 2);
  142.         size = ftell (fp);
  143.         fseek (fp, 0L, 0);    */
  144.         new = (struct let *) malloc (size + sizeof(struct let));
  145.         fread (&new[1], size, 1, fp);
  146.         fclose(fp);
  147.         if (already && !strcmp (m->area, m->name))
  148.             memcpy (new, m->mbox, (already + 1) * sizeof(struct let));
  149. #ifndef TNOS_68K
  150.         free (m->stdoutbuf);
  151.         m->stdoutbuf = 0;
  152. #endif
  153.         free (m->mbox);
  154.         m->mbox = new;
  155.         m->nmsgs = (int) (size / (long) sizeof(struct let));
  156.         isit = issysarea (m->area);
  157.         for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++)
  158.             if (isit)    {
  159.                 if ((cmsg->bid > m->lastread) && !(cmsg->status & BM_DELETE))
  160.                     m->newmsgs++;
  161.                 else
  162.                     cmsg->status |= BM_READ;
  163.                 if (cmsg->status & BM_ONHOLD)
  164.                     m->hmsgs++;
  165.             } else if (!(cmsg->status & BM_READ))
  166.                 m->newmsgs++;
  167.     }
  168.     else
  169.         m->nmsgs = 0;
  170.     return 0;
  171. }
  172.  
  173. /* list headers of a notesfile a message */
  174. /* Rearranged display - WG7J */
  175. int
  176. dolistnotes(argc,argv,p)
  177. int argc;
  178. char *argv[];
  179. void *p;
  180. {
  181. struct mbx *m;
  182. struct    let *cmsg;
  183. char    *cp, *s;
  184. char smtp_date[SLINELEN], smtp_from[SLINELEN];
  185. char smtp_subject[SLINELEN], tstring[LINELEN], type;
  186. char smtp_to[SLINELEN], smtp_bid[30];
  187. int start, stop;
  188. long    size;
  189. char    *area;
  190. int c,usemore=0,lin;
  191. #ifdef USERLOG
  192. long msgid;
  193. #endif
  194.  
  195.     m = (struct mbx *) p;
  196.  
  197.     /*If this user doesn't have read-permissions,
  198.      *we're not going to let him list anything - WG7J    */
  199.     if(m->privs & NO_READCMD)     {
  200.         tputs(Noperm);
  201.         return 0;
  202.     }
  203.  
  204.     if (m->mfile == NULLFILE) {
  205.         tputs(Nomail);
  206.         return 0;
  207.     }
  208.     if((m->stype == 'S' || m->stype == '$' || m->stype == '>' || m->stype == '<') && argc == 1) {
  209.         tputs("Search criterium needed!\n");
  210.         return 0;
  211.     }
  212.  
  213.     if((lin=m->morerows) != 0)
  214.         usemore = 1;    /* Display More prompt */
  215.  
  216.     area = strdup(m->area);
  217.     while((cp = strchr(area,'/')) != NULLCHAR)
  218.         *cp = '.';
  219.     bbscolorcls (m);
  220.     tprintf("Mail area: ");
  221.     bbscolorchange (m, "09");
  222.     tprintf (area);
  223.     bbscolorchange (m, "0B");
  224.     tprintf ("  %d ", m->nmsgs);
  225.     bbscolorchange (m, "0F");
  226.     tprintf ("message%s -  ",m->nmsgs == 1 ? " " : "s ");
  227.     bbscolorchange (m, "0B");
  228.     tprintf ("%d ", m->newmsgs);
  229.     bbscolorchange (m, "0F");
  230.     tprintf ("new\n\nStat  #        TO         FROM  DATE    SIZE SUBJECT\n");
  231.     free(area);
  232.  
  233.     stop = m->nmsgs;
  234.     if(m->stype == 'L') {        /* LL (List Latest) command */
  235.         if(argc > 1)
  236.             start = stop - atoi(argv[1]) + 1;
  237.         else
  238.             start = stop;
  239.         if (start < 1)
  240.             start = 1;
  241.     } else {
  242.         if((m->stype == 'A') || (m->stype == '>') || (m->stype == '<') || (m->stype == 'S') || (m->stype == '$')) {
  243.             start = 1;
  244.             stop = m->nmsgs;
  245.         } else {
  246.             if(argc > 1)
  247.                 start = atoi(argv[1]);
  248.             else
  249. #ifdef USERLOG
  250.                 start = m->nmsgs - m->newmsgs + 1;
  251. #else
  252.                 start = 1;
  253. #endif
  254.             if(argc > 2)
  255.                 stop = atoi(argv[2]);
  256.         }
  257.     }
  258.     if(stop > m->nmsgs)
  259.         stop = m->nmsgs;
  260.     if(start < 1 || start > stop)     {
  261.         if((m->stype == ' ') || (m->stype == 'M'))
  262.             tputs("No new mail.\n");
  263.         else
  264.             tputs("Invalid range.\n");
  265.         return 0;
  266.     }
  267.     for (cmsg = &m->mbox[start]; start <= stop; start++, cmsg++) {
  268.         *smtp_date = '\0';
  269.         *smtp_from = '\0';
  270.         *smtp_subject = '\0';
  271.         *smtp_to = '\0';
  272.         *smtp_bid = '\0';
  273.         type = ' ';
  274.         fseek(m->mfile,cmsg->start,0);
  275.         size = cmsg->size;
  276.         /* Be a little less selfish - WG7J */
  277.         pwait(NULL);
  278.  
  279. #ifdef USERLOG
  280. /* We need to get the id from the last message listed !
  281.  * m->mbox[i].start (ie cmsg->start) points to the 'From ' line
  282.  * next are the 'Received....' and 'ID...' lines
  283.  * These are thes line added by our smtp server.
  284.  * following the 'AA' is the number that we want ! - WG7J
  285.  */
  286.         if(start == stop) {
  287.             /*The 'From ' line*/
  288.             fgets(tstring,sizeof(tstring),m->mfile);
  289.             size -= strlen(tstring);
  290.             /*The 'Received' line*/
  291.             fgets(tstring,sizeof(tstring),m->mfile);
  292.             size -= strlen(tstring);
  293.             /*The 'ID' line*/
  294.             fgets(tstring,sizeof(tstring),m->mfile);
  295.             size -= strlen(tstring);
  296.             /* find id number */
  297. #ifndef nope
  298.             if((cmsg->bid > m->lastread) && (cmsg->bid > m->newlastread))
  299.                 m->newlastread = cmsg->bid;            
  300. #else
  301.             if((cp=strstr(tstring,"AA")) != NULLCHAR) {
  302.                 /*what follows is the message-number*/
  303.                 msgid = atol(cp+2);
  304.                 if((msgid > m->lastread) && (msgid > m->newlastread))
  305.                     m->newlastread = msgid;
  306.             }
  307. #endif
  308.         }
  309. #endif
  310.  
  311.         while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile) != NULLCHAR) {
  312.             pwait(NULL);
  313.             if (*tstring == '\n')   /* end of header */
  314.                 break;
  315.             size -= strlen(tstring);
  316.             rip(tstring);
  317.             /* handle continuation later */
  318.             if (*tstring == ' '|| *tstring == '\t')
  319.                 continue;
  320.             switch(htype(tstring)) {
  321.             case FROM:    cp = getaddress(tstring,0);
  322.                     strncpy(smtp_from,cp != NULLCHAR ? cp : "", 8);
  323.                     if((cp=strchr(smtp_from,'@')) != NULLCHAR)
  324.                         *cp = '\0';         /* get rid of @-host or @-bbs field */
  325.                     break;
  326.             case SUBJECT:    strncpy (smtp_subject,&tstring[9], 35);
  327.                     break;
  328.             case MSGID:    strncpy (smtp_bid,&tstring[12], 29);
  329.                     break;
  330.             case DATE:    if ((cp = strchr(tstring,',')) == NULLCHAR)
  331.                         cp = &tstring[6];
  332.                     else
  333.                         cp++;
  334.                     /* skip spaces */
  335.                     while (*cp == ' ')     cp++;
  336.                     if(strlen(cp) < 17)
  337.                         break;     /* not a valid length */
  338.                     s = smtp_date;
  339.                     /* copy day */
  340.                     if (atoi(cp) < 10 && *cp != '0')
  341.                         *s++ = ' ';
  342.                     else
  343.                         *s++ = *cp++;
  344.                     *s++ = *cp++;
  345.  
  346.                     *s++ = ' ';
  347.                     *s = '\0';
  348.                     while (*cp == ' ')
  349.                         cp++;
  350.                     strncat(s,cp,3);    /* copy month */
  351. #ifdef use_time
  352.                             cp += 3;
  353.                     while (*cp == ' ')
  354.                         cp++;
  355.                     /* skip year */
  356.                     while (isdigit(*cp))
  357.                         cp++;
  358.                     /* copy time */
  359.                     strncat(s,cp,6); /* space hour : min */
  360. #endif
  361.                             break;
  362.             case BBSTYPE:    type = tstring[16];
  363.                     break;
  364.             case TO:    strncpy (smtp_to,&tstring[4], 13);
  365.                     break;
  366.             case NOHEADER:    break;
  367.             }
  368.         }
  369.         if(m->stype == ' ' || m->stype == 'L' || m->stype == 'M' ||
  370.             m->stype == 'A' || (type == m->stype && m->stype != ' ') ||
  371.             ((m->stype == 'S') && (strstr(strlwr(smtp_subject),argv[1]) != NULLCHAR)) ||
  372.             ((m->stype == '<') && (strstr(strlwr(smtp_from),argv[1]) != NULLCHAR)) ||
  373.             ((m->stype == '$') && (strstr(strlwr(smtp_bid),argv[1]) != NULLCHAR)) ||
  374.             ((m->stype == '>') && (strstr(strlwr(smtp_to),argv[1]) != NULLCHAR)))         {
  375.                 lin--;
  376.                 if ((cmsg->status & BM_DELETE) && !(m->privs & SYSOP_CMD))
  377.                     strcpy (smtp_subject, "[DELETED]");
  378.                 bbscolorchange (m, "07");
  379.                 tprintf("%c%c%c%c%3d ",
  380.                     (start == m->current ? '>' : ' '),
  381.                     (cmsg->status & BM_ONHOLD ? 'H' :
  382.                     cmsg->status & BM_DELETE ? 'D' : ' '),
  383.                     (cmsg->status & BM_READ ? 'Y' : 'N'),
  384.                     (cmsg->status & BM_PERMANENT) ? 'P' : ' ',
  385.                     start);
  386.                 bbscolorchange (m, "0E");
  387.                 tprintf("%13.13s ",smtp_to);
  388.                 bbscolorchange (m, "0C");
  389.                 tprintf("%8.8s ",smtp_from);
  390.                 bbscolorchange (m, "07");
  391.                 tprintf("%-7.7s ",smtp_date);
  392.                 tprintf("%5ld ",cmsg->size);
  393.                 bbscolorchange (m, "0E");
  394.                 tprintf("%.34s\n", smtp_subject);
  395.         }
  396.         /* More prompting added - WG7J */
  397.         if(usemore && lin == 0)        {
  398.             if(m->type == TELNET || m->type == TIP)
  399.                 c = tkeywait("--More--",0);
  400.             else  /* For AX.25 and NET/ROM connects - WG7J */
  401.                 c = mykeywait(anymore, m);
  402.             if(c == -1 || c == 'q' || c == 'Q' || c == 'n' || c == 'N')
  403.                 break;
  404. #ifdef TNOS_68K
  405.             if(c == '\l' || c == '\r')
  406. #else
  407.             if(c == '\n' || c == '\r')
  408. #endif
  409.                 lin = 1;
  410.             else
  411.                 lin = m->morerows;
  412.  
  413.         }
  414.     }
  415.     return 0;
  416. }
  417.  
  418. /*  save msg on stream - if noheader set don't output the header */
  419. int
  420. msgtofile(m,msg,tfile,noheader)
  421. struct mbx *m;
  422. int msg;
  423. FILE *tfile;   /* already open for write */
  424. int noheader;
  425. {
  426.     char    tstring[LINELEN];
  427.     long     size;
  428.  
  429.     if (m->mfile == NULLFILE) {
  430.         tprintf(Nomail);
  431.         return -1;
  432.     }
  433.     fseek(m->mfile,m->mbox[msg].start,0);
  434.     size = m->mbox[msg].size;
  435.  
  436.     if (noheader) {
  437.         /* skip header */
  438.         while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  439.                != NULLCHAR) {
  440.             size -= strlen(tstring);
  441.             if (*tstring == '\n')
  442.                 break;
  443.         }
  444.     }
  445.     while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  446.            != NULLCHAR) {
  447.         size -= strlen(tstring);
  448.         fputs(tstring,tfile);
  449.         if (ferror(tfile)) {
  450.             tprintf("Error writing mail file\n");
  451.             return -1;
  452.         }
  453.     }
  454.     return 0;
  455. }
  456.  
  457. /* dodelmsg - delete message in current notesfile */
  458. /* Modified to allow the 'KM' command. 920307 -  WG7J */
  459. /* also handles holsing/releasing messages - KO4KS */
  460. int
  461. dodelmsg(argc,argv,p)
  462. int argc;
  463. char *argv[];
  464. void *p;
  465. {
  466.     struct mbx *m;
  467.     int msg,i;
  468.     char *myargv[NARG];
  469.     int myargc;
  470.     int maxmsg;
  471.     struct let *cmsg;
  472.     char *tmpbuf;
  473.  
  474.     m = (struct mbx *) p;
  475.  
  476.     /* If this user doesn't have read-permissions,
  477.      * we're not going to let him kill/hold anything;
  478.      * allow anyone to kill/hold messages in areas
  479.      * who's names start with 'nts' - WG7J
  480.      */
  481.     /* Check if we have permission to delete others mail */
  482.     if( (m->privs & NO_READCMD) || (m->privs & NO_SENDCMD) ||
  483.         ( !(m->privs & FTP_WRITE) &&
  484.             stricmp(m->area,m->name) &&
  485.             strnicmp(m->area,"nts",3)) ){
  486.         tputs(Noperm);
  487.         return 0;
  488.     }
  489.     if ((m->stype == 'A' || m->stype == 'H' || m->stype == 'P' || m->stype == 'T') && !(m->privs & SYSOP_CMD))    {
  490.         tputs(Noperm);
  491.         return 0;
  492.     }
  493.     if (m->stype == 'S')    {
  494.     myargc = msg = atoi(argv[1]);
  495.     i = atoi(argv[2]);
  496.     if ((argc < 3) || !msg || !i)
  497.             tputs(NoMsgs);
  498.     else    {
  499.         for ( ; myargc <= i; myargc++)    {
  500.             m->mbox[myargc].status |= BM_DELETE;
  501.             statusCtl (m->area, "ctl", &m->mbox[myargc], myargc, 0);
  502.         }
  503.         if (!issysarea (m->area))
  504.             m->change |= CHG_DELETE;
  505.         tprintf("Msgs %d to %d Killed.\n", msg, i);
  506.     }
  507.         return 0;
  508.     }
  509.     if (m->mfile == NULLFILE) {
  510.         tputs(Nomail);
  511.         return 0;
  512.     }
  513.     /*If this is the KM command, setup myargv[]
  514.      *to contain up to NARG message numbers - WG7J
  515.      */
  516.     if(m->stype == 'M') {
  517.         myargc = 1;
  518.         /* scan all messsages to find read ones */
  519.         maxmsg = min(m->nmsgs,NARG-1);
  520.         for(i=1;i<=maxmsg;i++){
  521.             cmsg = &m->mbox[i];
  522.             if(cmsg->status & BM_READ) { /*found a read msg!*/
  523.                 tmpbuf = mallocw(18); /*allocate space for the new argument*/
  524.                 myargv[myargc++] = itoa(i,tmpbuf,10);
  525.             }
  526.         }
  527.         if(myargc == 1) {
  528.             tputs(NoMsgs);
  529.             return 0;
  530.         }
  531.          argc = myargc;
  532.     } else {
  533.         if(argc == 1) {
  534.             tprintf("Usage: K%c #\n", m->stype);
  535.             return 0;
  536.         }
  537.         /*simply point to the old arguments*/
  538.         for(i=1;i<argc;i++)
  539.             myargv[i] = argv[i];
  540.     }
  541.  
  542.     for(i = 1; i < argc; ++i) {
  543.         msg = atoi(myargv[i]);
  544.         if(msg < 1 || msg > m->nmsgs) {
  545.             tprintf(Badmsg,msg);
  546.             continue;
  547.         }
  548.     switch (m->stype)    {
  549.         case 'U':    m->mbox[msg].status &= ~BM_DELETE;
  550.                 tprintf("Msg %d Un-Killed.\n", msg);
  551.                 break;
  552.         case 'A':    m->mbox[msg].status &= ~BM_ONHOLD;
  553.                 tprintf("Msg %d Available.\n", msg);
  554.                 break;
  555.         case 'H':    m->mbox[msg].status |= BM_ONHOLD;
  556.                 tprintf("Msg %d Held.\n", msg);
  557.                 break;
  558.         case 'T':    m->mbox[msg].status &= ~BM_PERMANENT;
  559.                 tprintf("Msg %d Temporary.\n", msg);
  560.                 break;
  561.         case 'P':    m->mbox[msg].status |= BM_PERMANENT;
  562.                 tprintf("Msg %d Permanent.\n", msg);
  563.                 break;
  564.         default :    m->mbox[msg].status |= BM_DELETE;
  565.                 tprintf("Msg %d Killed.\n", msg);
  566.                 if (!issysarea (m->area))
  567.                     m->change |= CHG_DELETE;
  568.                 break;
  569.     }
  570.     statusCtl (m->area, "ctl", &m->mbox[msg], msg, 0);
  571.     }
  572.     /* If this was 'KM'
  573.      * free the memory allocated for myargv[] - WG7J
  574.      */
  575.     if(m->stype == 'M') {
  576.         for(i=1;i<argc;i++)
  577.             free(myargv[i]);
  578.     }
  579.     return 0;
  580. }
  581.  
  582. struct clparms    {
  583.     int nostatus,
  584.         nodelete;
  585.       long *hostsize;
  586.        char name[20] ;         /* Name of remote station */
  587.        char area[64];        /* name of current mail area */
  588.       FILE *mfile;        /* mail data file pointer */
  589. struct let *mbox;
  590.         int nmsgs;        /* number of messages in this mail box */
  591.         int isbbs;
  592. };
  593.  
  594.  
  595. static void
  596. close_notes (a, b, c)
  597. int a;
  598. void *b, *c;
  599. {
  600. struct clparms *cl;
  601. struct    let *cmsg;
  602. char *line;
  603. char tstring[LINELEN], buf[256];
  604. char buf2[256];
  605. long size, diff;
  606. FILE    *nfile;
  607. int i, nextisBID, numwritten = 0;
  608. long msgid;
  609. char *cp;
  610. int foundstatus;
  611.  
  612.     cl = (struct clparms *) b;
  613.     line = tstring;
  614.     sprintf(buf,"%s/CONTROL/%s.ctl",Mailspool,cl->area);
  615.     remove (buf);
  616.  
  617.     fclose (cl->mfile);
  618.     sprintf(buf,"%s/%s.txt",Mailspool,cl->area);
  619.     sprintf(buf2,"%s/%s.bak",Mailspool,cl->area);
  620.     remove (buf2);        /* delete it here, just in case! */
  621.     rename (buf, buf2);
  622.     if ((cl->mfile = fopen(buf2,READ_TEXT)) == NULLFILE)    {
  623.         rmlock(Mailspool,cl->area);
  624.         free (cl);
  625.         return;
  626.     }
  627.     if ((nfile = fopen(buf,WRITE_TEXT)) == NULLFILE) {
  628.         fclose(cl->mfile);
  629.         rmlock(Mailspool,cl->area);
  630.         free (cl);
  631.         return;
  632.     }
  633.     /* copy tmp file back to notes file */
  634.     for (cmsg = &cl->mbox[1],i = 1; i <= cl->nmsgs; i++, cmsg++) {
  635.         fseek(cl->mfile,cmsg->start,0);
  636.         pwait (NULL);
  637.         cmsg->start = ftell(nfile);
  638.         size = cmsg->size;
  639.         diff = 0;
  640.         foundstatus = 0;
  641.         /* It is not possible to delete messages if nodelete is set */
  642.         if ((cmsg->status & BM_DELETE) && !cl->nodelete)
  643.             continue;
  644.         nextisBID = 0;
  645.         /* copy the header */
  646.         while (size > 0 && fgets(line,LINELEN,cl->mfile) != NULLCHAR) {
  647.             pwait(NULL);  /* can cause problems if exiting NOS */
  648.             if (nextisBID && (cp=strstr(line,"AA")) != NULLCHAR) {
  649.                 /*what follows is the message-number*/
  650.                 msgid = atol(cp+2);
  651.                 nextisBID = 0;
  652.                 }
  653.             if (!strncmp (line, Hdrs[RECEIVED], strlen(Hdrs[RECEIVED])))
  654.                 nextisBID = 1;
  655.             if (!strncmp (line, Hdrs[STATUS], strlen(Hdrs[STATUS])))
  656.                 foundstatus = 1;
  657.             size -= strlen(line);
  658.             if (*line == '\n') {
  659. #ifdef notagain
  660.                 if (cmsg->status & BM_FORWARDED)    {
  661.                     fprintf(nfile,"%s%s\n",Hdrs[XFORWARD],
  662.                         cl->name);
  663.                     diff += (strlen(Hdrs[XFORWARD]) + strlen(cl->name) + 1);
  664.                 }
  665. #endif
  666.                 if (!foundstatus && (cmsg->status & BM_READ) != 0 && !cl->nostatus)  {
  667.                     fprintf(nfile,"%sR\n",Hdrs[STATUS]);
  668.                     diff += (strlen(Hdrs[STATUS]) + 2);
  669.                 }
  670.                 fprintf(nfile,"\n");
  671.                 break;
  672.             }
  673.             fputs(line,nfile);
  674.             pwait(NULL);  /* can cause problems if exiting NOS */
  675.         }
  676.         pwait (NULL);
  677.         while (size > 0 && fgets(line,LINELEN,cl->mfile) != NULLCHAR) {
  678.             pwait(NULL);  /* can cause problems if exiting NOS */
  679.             if (!cl->nostatus && !strncmp (line, Hdrs[RRECEIPT], strlen(Hdrs[RRECEIPT]))
  680.                 && !strcmp (cl->name, cl->area) && (cmsg->status & BM_RRECEIPT))    {
  681.                     fputs("Return-Receipt-Sent\n", nfile);
  682.                     diff -= strlen(line);
  683.                     diff += 20;
  684.                 }
  685.                 else
  686.                     fputs(line,nfile);
  687.             size -= strlen(line);
  688.             pwait(NULL);   /* dont want no damaged files */
  689.             if (ferror(nfile)) {
  690.                 (void) fclose(nfile);
  691.                 fclose(cl->mfile);
  692.                 rmlock(Mailspool,cl->area);
  693.                 free (cl);
  694.                 return;
  695.             }
  696.         }
  697.         cmsg->status &= BM_READ;
  698.         cmsg->size += diff;
  699.         updateCtl (cl->area, cmsg);
  700.         fflush(nfile);
  701.         numwritten++;
  702.     }
  703.     if (!cl->isbbs && !stricmp(cl->name,cl->area))
  704.         *cl->hostsize = ftell(nfile); /* Update the size of our hosts' mailbox */
  705.                       /* potientially dangerous! */
  706.     /* remove a zero length file */
  707.     if (!numwritten)        {
  708.         (void) fclose(nfile);        
  709.         (void) unlink(buf);
  710.     } else
  711.         (void) fclose(nfile);
  712.     fclose (cl->mfile);
  713.     remove (buf2);        /* leave it around, for now! NOT! */
  714.     rmlock(Mailspool,cl->area);
  715.     free (cl->mbox);
  716.     free (cl);
  717.     pwait(NULL);
  718.     return;
  719. }
  720.  
  721.  
  722.  
  723. /* close the temp file while coping mail back to the mailbox */
  724. int
  725. closenotes(m)
  726. struct mbx *m;
  727. {
  728. int i, nostatus, nodelete = 0;
  729. struct clparms *cl;
  730.  
  731.     if (m->mfile == NULLFILE)
  732.         return 0;
  733.     nostatus = issysarea(m->area);
  734.  
  735.     /* Allow any user to delete from area names starting with 'nts' */
  736.     if(!strnicmp(m->area,"nts",3))
  737.         nostatus = 0;
  738.     if(!m->change || nostatus) {    /* no changes were made (or bulletin) */
  739.         mfclose(m);
  740.         m->mboxsize = 0;
  741.         return 0;
  742.     }
  743.     /* If this area is not our own private message area, then we will not add a
  744.      * Status line to indicate that the message has been read.
  745.      */
  746.     if (strcmp (m->area, m->name))    {
  747.         nostatus = 1;
  748.         /* Don't delete messages from public message areas unless you are
  749.          * a SYSOP.
  750.          */
  751.         nodelete = !(m->privs & SYSOP_CMD);
  752.         }
  753.     /* Allow any user to delete from area names starting with 'nts' */
  754.     if(!strnicmp(m->area,"nts",3))
  755.         nodelete = 0;        
  756.     /* If not a SYSOP, not an "nts" area, not our area, AND deletions, must be BBS forward */
  757.     if (nodelete && (m->change & CHG_DELETE))    {
  758.         nodelete = 0;
  759.         log(-1,"MBOX forwarding rewrite of personal area '%s' by %s ", m->area, m->name);
  760.     }
  761.  
  762.     if(nostatus && nodelete)    {
  763.         mfclose(m);
  764.         m->mboxsize = 0;
  765.         return 0;
  766.     }
  767.     scanmail(m);
  768.     if(lockit(m))
  769.         return -1;
  770.     cl = (struct clparms *) malloc (sizeof (struct clparms));
  771.     cl->nodelete = nodelete;
  772.     cl->nostatus = nostatus;
  773.     cl->hostsize = &m->mysize;
  774.     cl->isbbs = (m->sid & MBX_SID);
  775.     strcpy (cl->name, m->name);
  776.     strcpy (cl->area, m->area);
  777.     cl->mfile = m->mfile;
  778.     cl->nmsgs = m->nmsgs;
  779.     cl->mbox = m->mbox;
  780.     newproc("Closing notefile", 2560, close_notes, 0, cl, 0, 0);
  781.     pwait(NULL);
  782.      m->mfile = NULLFILE;
  783.      m->mbox = (struct let *) 0;
  784.     mfclose(m);
  785.     m->mboxsize = 0;
  786.     return 0;
  787. }
  788.  
  789.  
  790. /* Returns 1 if name is in the given area file, 0 otherwise */
  791. static int
  792. is_area(name, listfile)
  793. char *name, *listfile;
  794. {
  795. char buf[LINELEN], *cp;
  796. FILE *fp;
  797.  
  798.     if((fp = fopen(listfile,READ_TEXT)) == NULLFILE)
  799.         return 0;
  800.     while(fgets(buf,sizeof(buf),fp) != NULLCHAR)     {
  801.         /* The first word on each line is all that matters */
  802.         if(isalnum(buf[0]))     { /* skip comments */
  803.                 if((cp = strpbrk(buf," \t")) != NULLCHAR)
  804.                 *cp = '\0';
  805.                 /*This could be a line with just the area name,
  806.                  *ie terminated with 'CR/LF' - WG7J
  807.                  */
  808.                 if((cp = strchr(buf,'\n')) != NULLCHAR)
  809.                 *cp = '\0';
  810.                 if(stricmp(name,buf) == 0) {    /* found it */
  811.                 fclose(fp);
  812.                 return 1;
  813.                 }
  814.             }
  815.         }
  816.     fclose(fp);
  817.     return 0;
  818. }
  819.  
  820. /* Returns 1 if name is a public message Area, 0 otherwise */
  821. int
  822. isarea(name)
  823. char *name;
  824. {
  825.     return (is_area (name, Arealist));
  826. }
  827.  
  828. /* Returns 1 if name is a public message Area, 0 otherwise */
  829. int
  830. issysarea(name)
  831. char *name;
  832. {
  833.     return (is_area (name, AreaSlist));
  834. }
  835.  
  836. int
  837. lockit(m)
  838. struct mbx *m;
  839. {
  840.     int c, cnt = 0;
  841.  
  842.     while(mlock(Mailspool,m->area)) {
  843.         mspause(1000L/MSPTICK);    /* Wait one second */
  844.         if(++cnt == 10) {
  845.             char buf[80];
  846.             sprintf (buf, "Mail file '%s' is busy, Abort or *Retry ? ", m->area);
  847.             cnt = 0;
  848.             c = tkeywait(buf,1);
  849.             if (c == 'A' || c == 'a' || c == EOF) {
  850.                 mfclose(m);
  851.                 return 1;
  852.             }
  853.         }
  854.     }
  855.     return 0;
  856. }
  857.  
  858. /* read the next message or the current one if new */
  859. int
  860. doreadnext(argc,argv,p)
  861. int argc;
  862. char *argv[];
  863. void *p;
  864. {
  865.     struct mbx *m;
  866.     char buf[10], *newargv[2];
  867.     m = (struct mbx *) p;
  868.     if (m->mfile == NULLFILE)
  869.         return 0;
  870.     if ((m->mbox[m->current].status & BM_READ) != 0) {
  871.         if (m->current == 1 && m->anyread == 0)
  872.             ;
  873.         else if (m->current < m->nmsgs) {
  874.             m->current++;
  875.         } else {
  876.             tprintf("Last message\n");
  877.             return 0;
  878.         }
  879.     }
  880.     sprintf(buf,"%d",m->current);
  881.     newargv[0] = "read";
  882.     newargv[1] = buf;
  883.     return doreadmsg(2,newargv,p);
  884. }
  885.  
  886. extern int MbRead;
  887.  
  888. /* display message on the crt given msg number */
  889. /* Modified to allow the 'RM' command, 920307 - WG7J */
  890. int
  891. doreadmsg(argc,argv,p)
  892. int argc;
  893. char *argv[];
  894. void *p;
  895. {
  896.     struct mbx *m;
  897.     register int c, col, lin;
  898.     unsigned char    buf[MAXBUF+2], *cp, *cp2;
  899.     char *subj = 0, *theto = 0;
  900.     int msg, cnt, i, usemore=0, verbose, mbxheader, pathcol;
  901.     int    header, lastheader;
  902.     long     size;
  903.     char *myargv[NARG];
  904.     int myargc;
  905.     int maxmsg;
  906.     struct let *cmsg;
  907.     char *tmpbuf;
  908.     char *returnreceipt;
  909. #ifdef nope   /* was USERLOG */
  910.     long msgid;
  911. #endif
  912.  
  913.     m = (struct mbx *) p;
  914.  
  915.     /*Check for read-permissions - WG7J */
  916.     if(m->privs & NO_READCMD) {
  917.         tputs(Noperm);
  918.         return 0;
  919.     }
  920. #ifdef MBFWD
  921.     if (m->stype == 'O')
  922.         return (dombroute (argc, argv, p));
  923. #endif
  924.     if (m->mfile == NULLFILE) {
  925.         tprintf(Nomail);
  926.         return 0;
  927.     }
  928.     if((lin=m->morerows) != 0)
  929.         usemore = 1;    /* Display More prompt */
  930.  
  931.     /*If this is the RM or VM command, setup myargv[]
  932.      *to contain up to NARG message numbers - WG7J
  933.      */
  934.     if(m->stype == 'M') {
  935.         myargc = 1;
  936.         /* scan all messsages to find unread ones */
  937.         maxmsg = min(m->nmsgs,NARG-1);
  938.         for(i=1;i<=maxmsg;i++){
  939.             cmsg = &m->mbox[i];
  940.             if(!(cmsg->status & BM_READ)) { /*found an unread msg!*/
  941.                 tmpbuf = mallocw(18); /*allocate space for the new argument*/
  942.                 myargv[myargc++] = itoa(i,tmpbuf,10);
  943.             }
  944.         }
  945.         argc = myargc;
  946.     } else {
  947.         /*simply point to the old arguments*/
  948.         for(i=1;i<argc;i++)
  949.             myargv[i] = argv[i];
  950.     }
  951.     if(argc == 1) {
  952.         tputs("Usage: Read/Verbose #\n");
  953.         return 0;
  954.     }
  955.     m->state = MBX_READ;
  956.     for(i = 1; i < argc; ++i) {
  957.         msg = atoi(myargv[i]);
  958.         if( msg < 1 || msg > m->nmsgs) {
  959.             tprintf(Badmsg,msg);
  960.             goto iamdone;
  961.         }
  962.         MbRead++;
  963.         fseek(m->mfile,m->mbox[msg].start,0);
  964. #ifdef nope  /* was USERLOG */
  965.         /* Check the ID number of this message and
  966.          * adjust new lastread count, if needed - WG7J
  967.          */
  968.         fgets(buf,MAXBUF+2,m->mfile);    /* the 'From ' line */
  969.         fgets(buf,MAXBUF+2,m->mfile);    /* the 'Received: ' line */
  970.         fgets(buf,MAXBUF+2,m->mfile);    /* the ' ID' line */
  971.         /* find id number */
  972.         if((cp=strstr(buf,"AA")) != NULLCHAR) {
  973.         /*what follows is the message-number*/
  974.             msgid = atol(cp+2);
  975.         if((msgid > m->lastread) && (msgid > m->newlastread))
  976.                 m->newlastread = msgid;
  977.             }
  978.         fseek(m->mfile,m->mbox[msg].start,0);
  979. #endif
  980. #ifdef USERLOG
  981.             if((m->mbox[msg].bid > m->lastread) && (m->mbox[msg].bid > m->newlastread))
  982.                 m->newlastread = m->mbox[msg].bid;
  983. #endif
  984.  
  985.     m->anyread = 1;
  986.     returnreceipt = 0;
  987.         size = m->mbox[msg].size;
  988.         m->current = msg;
  989.         header = NOHEADER;
  990.         mbxheader = 0;
  991.         if((*argv[0] == 'v') || (m->stype == 'H'))
  992.             verbose = 1;    /* display all header lines */
  993.         else
  994.             verbose = 0;
  995.  
  996.     m->inmessage = 1;
  997.     if(m->stype != 'M')
  998.         bbscolorcls (m);
  999.     bbscolorchange (m, "07");
  1000.         tprintf("Message #%d %s\n", msg,
  1001.             m->mbox[msg].status & BM_ONHOLD ? "[On Hold - Awaiting Review of SYSOP]" :
  1002.             m->mbox[msg].status & BM_DELETE ? "[Deleted]" : "");
  1003.  
  1004.     if ((m->mbox[msg].status & (BM_ONHOLD | BM_DELETE)) && !(m->privs & SYSOP_CMD))
  1005.             continue;
  1006.  
  1007.         /* When you have sysop privs,
  1008.          * only mark your own private area as read and changed.
  1009.          * other areas, only mark as read, NOT changed !
  1010.          * for regular users, simply mark all as read and changed.
  1011.          * That way sysops can read other's mail without
  1012.          * marking stuff read that really wasn't read by
  1013.          * the right person !
  1014.          * for regular users, simply mark as read.
  1015.          * 910312 - WG7J
  1016.          */
  1017.         if(!(m->mbox[msg].status & BM_READ)) {
  1018.             m->mbox[msg].status |= BM_READ;
  1019.                 /* regular users */
  1020.             if(!issysarea (m->area) && (!(m->privs & SYSOP_CMD) || \
  1021.                ((m->privs & SYSOP_CMD) && !strcmp(m->name,m->area)))) /*sysops*/
  1022.             m->change |= CHG_READ;
  1023.             m->newmsgs--;
  1024.         }
  1025.         --lin;
  1026.         col = 0;
  1027.         while (!feof(m->mfile) && size > 0) {
  1028.             for (col = 0;  col < MAXBUF;) {
  1029.                 c = getc(m->mfile);
  1030.                 size--;
  1031.                 if (feof(m->mfile) || size == 0) /* end this line */
  1032.                     break;
  1033.                 if (c == '\t') {
  1034.                     cnt = col + 8 - (col & 7);
  1035.                     if (cnt >= MAXBUF) /* end this line */
  1036.                         break;
  1037.                     while (col < cnt)
  1038.                         buf[col++] = ' ';
  1039.                 } else {
  1040.                     if (c == '\n')
  1041.                         break;
  1042.                     buf[col++] = c;
  1043.                 }
  1044.             }
  1045.             if(col < MAXBUF)
  1046.                 buf[col++] = '\n';
  1047.             buf[col] = '\0';
  1048.             if(mbxheader > 0) {
  1049.                  /* Digest R: lines and display as a Path: line */
  1050.                  if(strnicmp(buf,"R:",2) != 0 ||
  1051.                 (cp = strchr(buf,'@')) == NULLCHAR) {
  1052.                   tputc('\n');
  1053.                   mbxheader = -1; /* don't get here again */
  1054.                   verbose = 1;
  1055.                  }
  1056.                  else {
  1057.                   if(*(++cp) == ':')
  1058.                        ++cp;
  1059.                   for(cp2 = cp; isalnum(*cp2); ++cp2)  ;
  1060.                   *cp2 = '\0';
  1061.                   if(mbxheader++ == 1) {
  1062.                        tputs(Hdrs[PATH]);
  1063.                        pathcol = 5;
  1064.                        --lin;
  1065.                   }
  1066.                   else {
  1067.                        tputc('!');
  1068.                        if(++pathcol + strlen(cp) > MAXCOL-3){
  1069.                         tputs("\n      ");
  1070.                         pathcol = 5;
  1071.                         --lin;
  1072.                        }
  1073.                   }
  1074.                   tputs(cp);
  1075.                   pathcol += strlen(cp);
  1076.                   ++lin;    /* to allow for not printing it later */
  1077.                  }
  1078.             }
  1079.             if(col == 1 && !mbxheader)    {
  1080.                  bbscolorchange (m, "0B");
  1081.                  /* last header line reached */
  1082.                  if (!verbose)
  1083.                      mbxheader = 1;
  1084.             }
  1085.             if(verbose)
  1086. /*                tputs(buf);    */
  1087.                 colorprintf (NULLCHAR, m->usecolor, buf);
  1088.             if (!strncmp (Hdrs[RRECEIPT], buf, strlen(Hdrs[RRECEIPT])))
  1089.                 returnreceipt = strdup(&buf[strlen(Hdrs[RRECEIPT])]);
  1090.             if(!verbose && !mbxheader){
  1091.                 lastheader = header;
  1092.                 if(!isspace(*buf))
  1093.                     header = htype(buf);
  1094.                 else
  1095.                     header = lastheader;
  1096.                 switch(header) {
  1097.                 case SUBJECT:    subj = strdup (&buf[strlen(Hdrs[SUBJECT]) - 4]);
  1098.                         tputs(buf);
  1099.                         break;
  1100.                 case TO:        theto = strdup (&buf[strlen(Hdrs[TO])]);
  1101.                 case CC:
  1102.                 case FROM:
  1103.                 case DATE:
  1104.                 case REPLYTO:
  1105.                 case APPARTO:
  1106.                 case ERRORSTO:
  1107.                 case XMAILGROUP:
  1108.                 case ORGANIZATION:
  1109.                     tputs(buf);
  1110.                     break;
  1111.                 default:
  1112.                     ++lin;
  1113.                 }
  1114.             }
  1115.             col = 0;
  1116.             if(usemore && --lin == 0){
  1117.                 if(m->type == TELNET || m->type == TIP)
  1118.                     c = tkeywait("--More--",0);
  1119.                 else  /* For AX.25 and NET/ROM connects - WG7J */
  1120.                     c = mykeywait(anymore, m);
  1121.                 lin = m->morerows;
  1122.                 if(c == -1 || c == 'q' || c == 'Q')
  1123.                     break;
  1124. #ifdef TNOS_68K
  1125.                 if(c == '\l' || c == '\r')
  1126. #else
  1127.                 if(c == '\n' || c == '\r')
  1128. #endif
  1129.                     lin = 1;
  1130.             }
  1131.         }
  1132.     if (returnreceipt && !(m->mbox[msg].status & BM_RRECEIPT))    {
  1133.         struct mbx *mm;
  1134.         m->mbox[msg].status |= BM_RRECEIPT;
  1135.         rip (returnreceipt);    /* strip off <CR> */
  1136.         tprintf ("[Sending return receipt to '%s']\n", returnreceipt);
  1137.         mm = (struct mbx *) malloc (sizeof (struct mbx));
  1138.         mm->tomsgid = mm->date = mm->origbbs = mm->tofrom = NULLCHAR;
  1139.         mm->origto = returnreceipt;
  1140.         mm->subject = subj;
  1141.         rip (subj);    /* strip off <CR> */
  1142.         subj[0] = subj[1] = 'R';
  1143.         subj[2] = ':';
  1144.         subj[3] = ' ';
  1145.         mm->stype = 'P';
  1146.         strcpy (mm->name, m->name);
  1147.         if ((mm->tfile = tmpfile()) != NULLFILE)    {
  1148.             struct list *cclist = NULLLIST;
  1149.             char fullfrom[MBXLINE];
  1150.             addlist(&cclist, returnreceipt, 0, returnreceipt);
  1151.             sprintf (fullfrom, "%s@%s", m->name, Hostname);
  1152.             mbx_data (mm, NULLLIST, NULLCHAR);
  1153.             rip (theto);    /* strip off the <CR> */
  1154.             fprintf (mm->tfile, "Message received - Originally addressed to: '%s'\n", theto);
  1155.             fseek(mm->tfile, 0L, 0);    /* rewind file */
  1156.             queuejob (mm->tfile, Hostname, cclist, fullfrom);
  1157.             fclose (mm->tfile);
  1158.             del_list(cclist);
  1159.             smtptick(NULL);        /* wake up SMTP to send mail */
  1160.             }
  1161.         free (mm);
  1162.         free(returnreceipt);
  1163.         }
  1164.     free (subj);
  1165.     free (theto);
  1166.     m->inmessage = 0;
  1167.     }
  1168. iamdone:
  1169.     /* If this was 'RM' or 'VM',
  1170.      * free the memory allocated for myargv[] - WG7J
  1171.      */
  1172.     if(m->stype == 'M') {
  1173.         for(i=1;i<argc;i++)
  1174.             free(myargv[i]);
  1175.     }
  1176.     return 0;
  1177. }
  1178.  
  1179. /* Set up m->to when replying to a message. The subject is returned in
  1180.  * m->line.
  1181.  */
  1182. int
  1183. mbx_reply(argc,argv,m,cclist,rhdr)
  1184. int argc;
  1185. char *argv[];
  1186. struct mbx *m;
  1187. struct list **cclist;    /* Pointer to buffer for pointers to cc recipients */
  1188. char **rhdr;        /* Pointer to buffer for extra reply headers */
  1189. {
  1190. char subject[MBXLINE], *msgid = NULLCHAR, *date = NULLCHAR;
  1191. char *cp;
  1192. int msg, lastheader, header = NOHEADER;
  1193. long size;
  1194.  
  1195.     /* Free anything that might be allocated
  1196.      * since the last call to mbx_to() or mbx_reply()
  1197.      */
  1198.     free(m->to);
  1199.     m->to = NULLCHAR;
  1200.     free(m->tofrom);
  1201.     m->tofrom = NULLCHAR;
  1202.     free(m->tomsgid);
  1203.     m->tomsgid = NULLCHAR;
  1204.     free(m->origto);
  1205.     m->origto = NULLCHAR;
  1206.     subject[0] = '\0';
  1207.  
  1208.     if(argc == 1)
  1209.          msg = m->current;
  1210.     else
  1211.          msg = atoi(argv[1]);
  1212.     if (m->mfile == NULLFILE) {
  1213.          if(m->sid & MBX_SID)
  1214.           tputs("NO - ");
  1215.         tputs(Nomail);
  1216.         return 0;
  1217.     }
  1218.     if(msg < 1 || msg > m->nmsgs) {
  1219.          if(m->sid & MBX_SID)
  1220.           tputs("NO - ");
  1221.          tputs(Badmsg);
  1222.          return -1;
  1223.     }
  1224.     fseek(m->mfile,m->mbox[msg].start,0);
  1225.     size = m->mbox[msg].size;
  1226.     m->current = msg;
  1227.     while(size > 0 && fgets(m->line,MBXLINE-1,m->mfile) != NULLCHAR) {
  1228.          size -= strlen(m->line);
  1229.          if(m->line[0] == '\n')    /* end of header */
  1230.           break;
  1231.          rip(m->line);
  1232.          lastheader = header;
  1233.          if(!isspace(m->line[0])) {
  1234.           header = htype(m->line);
  1235.           lastheader = NOHEADER;
  1236.          }
  1237.          switch(header) {
  1238.          case SUBJECT:
  1239.           if(strlen(m->line) > 11 && !strnicmp(&m->line[9],"Re:",3))
  1240.                strcpy(subject,&m->line[9]);
  1241.           else
  1242.                sprintf(subject,"Re: %s",&m->line[9]);
  1243.           break;
  1244.          case FROM:
  1245.           if(m->to == NULLCHAR && (cp = getaddress(m->line,0)) !=
  1246.              NULLCHAR)
  1247.                m->to = strdup(cp);
  1248.           break;
  1249.          case REPLYTO:
  1250.           if((cp = getaddress(m->line,0)) != NULLCHAR) {
  1251.                free(m->to);
  1252.                m->to = strdup(cp);
  1253.           }
  1254.           break;
  1255.          case MSGID:
  1256.           free(msgid);
  1257.           msgid = strdup(&m->line[12]);
  1258.           break;
  1259.          case DATE:
  1260.           free(date);
  1261.           date = strdup(&m->line[6]);
  1262.           break;
  1263. #ifdef notdef
  1264.          /* don't want a reply back to myself - WG7J */
  1265.          case TO:
  1266.          case APPARTO:
  1267. #endif
  1268.          case CC:
  1269.           /* Get addresses on To, Cc and Apparently-To lines */
  1270.           cp = m->line;
  1271.           m->line[strlen(cp)+1] = '\0';    /* add extra null at end */
  1272.           for(;;) {
  1273.                if((cp = getaddress(cp,lastheader == header ||
  1274.                cp != m->line)) == NULLCHAR)
  1275.                     break;
  1276.                addlist(&cclist,cp,0,cp);
  1277.                /* skip to next address, if any */
  1278.                cp += strlen(cp) + 1;
  1279.           }
  1280.           break;
  1281.          }
  1282.     }
  1283.     if(msgid != NULLCHAR || date != NULLCHAR) {
  1284.          *rhdr = mallocw(LINELEN);
  1285.          sprintf(*rhdr,"In-Reply-To: your message ");
  1286.          if(date != NULLCHAR) {
  1287.           sprintf(m->line,"of %s.\n",date);
  1288.           strcat(*rhdr,m->line);
  1289.           if(msgid != NULLCHAR)
  1290.                strcat(*rhdr,"             ");
  1291.          }
  1292.          if(msgid != NULLCHAR) {
  1293.           sprintf(m->line,"%s\n",msgid);
  1294.           strcat(*rhdr,m->line);
  1295.          }
  1296.          free(msgid);
  1297.          free(date);
  1298.     }
  1299.     strcpy(m->line,subject);
  1300.     return 0;
  1301. }
  1302.  
  1303. #ifdef USERLOG
  1304.  
  1305. /*get the last message listed/read
  1306.  *from the areaname.USR file
  1307.  *keeps track for each user.
  1308.  *February '92, WG7J
  1309.  */
  1310. void
  1311. getlastread(m)
  1312. struct mbx *m;
  1313. {
  1314.     FILE *Alog;
  1315.     char buf[256];
  1316.     char *cp;
  1317.     int found=0;
  1318.  
  1319.     m->lastread = m->newlastread = 0L;
  1320.  
  1321.     sprintf(buf,"%s/USERS/%s.usr",Mailspool,m->area);
  1322.     if ((Alog = fopen(buf,"r+")) == NULLFILE) {
  1323.         /* USR file doesn't exist, create it */
  1324.         if((Alog = fopen(buf,"w")) == NULLFILE)
  1325.             return;
  1326.         /* Add this user as first one */
  1327.         sprintf(buf,"%s 0\n",m->name);
  1328.         fputs(buf,Alog);
  1329.         fclose(Alog);
  1330.         return;
  1331.     }
  1332.     /*Find user in the usr file for this area*/
  1333.     for(;;) {
  1334.         if(fgets(buf,sizeof(buf),Alog) == NULLCHAR)
  1335.             break;
  1336.         if((cp=strchr(buf,' ')) != NULLCHAR)
  1337.             *cp = '\0';
  1338.         if(!stricmp(m->name,buf)) {
  1339.             /*found user*/
  1340.             cp++;
  1341.             while(*cp == ' ')   /*skip blanks*/
  1342.                 cp++;
  1343.             m->lastread = atol(cp);
  1344.             found = 1;
  1345.             break;
  1346.         }
  1347.     }
  1348.     if(!found) {
  1349.         /*Add user*/
  1350.         sprintf(buf,"%s 0\n",m->name);
  1351.         fputs(buf,Alog);
  1352.     }
  1353.     fclose(Alog);
  1354.     return;
  1355. }
  1356.  
  1357. /* Write the new last read id number to the USR file - WG7J
  1358.  * only update if this is not a bbs,
  1359.  * current area is a public area and not 'help',
  1360.  * or anything that starts with 'sys',
  1361.  * and a new message was actually listed/read
  1362.  */
  1363. void
  1364. setlastread(m)
  1365. struct mbx *m;
  1366. {
  1367. FILE *Alog, *tfile;
  1368. char buf[256];
  1369. char tmpname[80];
  1370. char *cp;
  1371. int doit = 0;
  1372.  
  1373.     if((m->sid & MBX_SID) || (m->newlastread <= m->lastread) )
  1374.         return;
  1375.  
  1376. /*    if(issysarea(m->area))
  1377.         if ((m->privs & MBX_SYSOP) || (stricmp(m->area, "help")))
  1378.             doit = 1;    */
  1379.       if(isarea(m->area) && strcmp(m->area, "help"))
  1380.             doit = 1;
  1381.       if ((m->privs & SYSOP_CMD) && issysarea(m->area))
  1382.             doit = 1;
  1383.  
  1384.       if (doit)        {
  1385.  
  1386. #ifdef notdef
  1387.     tprintf("SETLAST: %d\n",m->newlastread);
  1388. #endif
  1389.  
  1390.  
  1391.         sprintf(buf,"%s/USERS/%s.usr",Mailspool,m->area);
  1392.  
  1393.         /* Rename the USR file to a tempfile */
  1394.         tmpnam(tmpname);
  1395.         if(rename(buf,tmpname))
  1396.             /* Can't rename ??? */
  1397.             return;
  1398.  
  1399.         if((Alog = fopen(buf,"w")) == NULLFILE) {
  1400.             /* can't creat new USR file ???*/
  1401.             rename(tmpname,buf);    /* try to undo the damage */
  1402.             return;
  1403.         }
  1404.  
  1405.         if((tfile = fopen(tmpname,"r")) == NULLFILE)
  1406.             /* can't open renamed file ??? */
  1407.             return;
  1408.  
  1409.         /*Write all users back, but update this one!*/
  1410.         while(fgets(buf,sizeof(buf),tfile) != NULLCHAR) {
  1411.             if((cp=strchr(buf,' ')) != NULLCHAR)
  1412.                 *cp = '\0';
  1413.             if(!stricmp(m->name,buf)) {
  1414.                 /*found this user*/
  1415.                 sprintf(buf,"%s %lu\n",m->name,m->newlastread);
  1416.             } else
  1417.                 *cp = ' '; /* restore the space !*/
  1418.             fputs(buf,Alog);
  1419.         }
  1420.         fclose(tfile);
  1421.         unlink(tmpname);
  1422.         fclose(Alog);
  1423.     }
  1424.     return;
  1425. }
  1426.  
  1427. #endif /*USERLOG*/
  1428.  
  1429. void
  1430. scanmail(m)         /* Get any new mail */
  1431. struct mbx *m;
  1432. {
  1433. long diff;
  1434.  
  1435.     if ((diff = isnewmail(m)) == 0L)
  1436.         return;
  1437.     if(lockit(m))
  1438.         return;
  1439.     initnotes(m);
  1440.     rmlock(Mailspool,m->area);
  1441. }
  1442.  
  1443. /* Check the current mailbox to see if new mail has arrived.
  1444.  * Returns the difference in size.
  1445.  */
  1446. static long
  1447. isnewmail(m)
  1448. struct mbx *m;
  1449. {
  1450. char buf[256];
  1451.  
  1452.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  1453.     return fsize(buf) - m->mboxsize;
  1454. }
  1455.  
  1456. /* Check if the private mail area has changed */
  1457. long
  1458. isnewprivmail(m)
  1459. struct mbx *m;
  1460. {
  1461. long cnt;
  1462. char buf[256];
  1463.  
  1464.     sprintf(buf,"%s/%s.txt",Mailspool,m->name);
  1465.     cnt = m->mysize;
  1466.     m->mysize = fsize(buf);
  1467.     return m->mysize - cnt; /* != 0 not more than once */
  1468. }
  1469.  
  1470.  
  1471. void
  1472. notifynewmail (m)
  1473. struct mbx *m;
  1474. {    /* not a BBS, but from within ANY area */
  1475.     if (!(m->sid & MBX_SID) && (isnewprivmail(m) > 0L))    {
  1476.         tprintf("\007You have new mail in your personal area (%s). Please Kill when read!\n", m->name);
  1477.         usflush(Curproc->output);
  1478.     }
  1479. }
  1480.  
  1481. #endif
  1482.  
  1483. /* This function returns the length of a file. The proper thing would be
  1484.  * to use stat(), but it fails when using DesqView together with Turbo-C
  1485.  * code.
  1486.  */
  1487. long
  1488. fsize(name)
  1489. char *name;
  1490. {
  1491. long cnt;
  1492. FILE *fp;
  1493.  
  1494.     if((fp = fopen(name,READ_TEXT)) == NULLFILE)
  1495.         return -1L;
  1496.     fseek(fp,0L,2);
  1497.     cnt = ftell(fp);
  1498. /*    cnt = filelength (fileno(fp)); */
  1499.     fclose(fp);
  1500.     return cnt;
  1501. }
  1502.  
  1503. /* close the temporary mail file */
  1504. static void
  1505. mfclose(m)
  1506. struct mbx *m;
  1507. {
  1508.     if(m->mfile != NULLFILE)
  1509.         fclose(m->mfile);
  1510.     m->mfile = NULLFILE;
  1511. #ifdef SETVBUF
  1512.     free(m->stdoutbuf);
  1513.     m->stdoutbuf = NULLCHAR;
  1514. #endif
  1515. }
  1516.  
  1517.  
  1518. /* erase a previous prompt via backspaces */
  1519. void
  1520. backEmUp (len)
  1521. int len;
  1522. {
  1523. int i;
  1524.     /* Get rid of the prompt */
  1525.     for(i=len;i != 0;i--)
  1526.         tputc('\b');
  1527.     for(i=len;i != 0;i--)
  1528.         tputc(' ');
  1529.     for(i=len;i != 0;i--)
  1530.         tputc('\b');
  1531.     tflush ();
  1532. }
  1533.  
  1534.  
  1535. /* Print prompt and read one character, telnet version */
  1536. int
  1537. tkeywait(prompt,flush)
  1538. char *prompt;    /* Optional prompt */
  1539. int flush;    /* Flush queued input? */
  1540. {
  1541.     int c, oldimode,oldomode;
  1542.  
  1543.     if(flush && socklen(Curproc->input,0) != 0)
  1544.         recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0); /* flush */
  1545.     if(prompt == NULLCHAR)
  1546.         prompt = "Hit enter to continue"; 
  1547.     tprintf("%s%c%c%c",prompt,IAC,WILL,TN_ECHO);
  1548.     usflush(Curproc->output);
  1549.  
  1550.     /* discard the response */
  1551.  
  1552.     oldimode = sockmode(Curproc->input,SOCK_BINARY);
  1553.     oldomode = sockmode(Curproc->output,SOCK_BINARY);
  1554.  
  1555.     while((c = rrecvchar(Curproc->input)) == IAC){
  1556.         c = rrecvchar(Curproc->input);
  1557.         if(c > 250 && c < 255)
  1558.             rrecvchar(Curproc->input);
  1559.     }
  1560.  
  1561.     sockmode(Curproc->output,oldomode);
  1562.     sockmode(Curproc->input,oldimode);
  1563.  
  1564.     backEmUp (strlen(prompt));
  1565.     tprintf("%c%c%c",IAC,WONT,TN_ECHO);
  1566.     usflush(Curproc->output);
  1567.     return c;
  1568. }
  1569.  
  1570. /* Print -more- prompt and read reply,
  1571.  * AX.25 and NETROM version - WG7J
  1572.  * <CR> is taken as a 'Yes'
  1573.  */
  1574. int
  1575. mykeywait(prompt,m)
  1576. char *prompt;
  1577. struct mbx *m;
  1578. {
  1579.     tputs(prompt);
  1580.     usflush(Curproc->output);
  1581.     if(recvline(m->user, m->line, MBXLINE) == -1) {
  1582.         return -1;
  1583.     }
  1584.     /* Only 'N' or 'n' really matters */
  1585.     if((*m->line == 'N') || (*m->line == 'n'))
  1586.         return -1;
  1587.     return 0;
  1588. }
  1589.